#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/kthread.h>


struct sr501_struct{
    int gpio;                    /* 记录gpio号 */
    int flag;
    int irq;
    struct gpio_desc *gpiod;     /* gpio描述符 */
};

static struct sr501_struct *sensor_sr501;

/* 1-确定主设备号                                                                 */
static int major = 0;
static int status = 0;  /* 保存状态 */

static struct class *sr501_class;
struct fasync_struct *sr501_fasync;    /* 异步通知 */
static struct task_struct *sr501_task;

static DECLARE_WAIT_QUEUE_HEAD(sr501_waitqueue);

static int sensor_sr501_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    int err, len;
    
    len = (size < 4) ? 4 : size;
    wait_event_interruptible(sr501_waitqueue, status);
    err = copy_to_user(buf, &status, len);
    status = 0;

    return len;
}

/* sr501 异步通知驱动 */
static int sensor_sr501_drv_fasync(int fd, struct file *filp, int mode)
{
    if(fasync_helper(fd, filp, mode, &sr501_fasync) >= 0) {
        return 0;
    }
    else {
        return -EIO;
    }
}

/* kthread 线程函数 */
static int sensor_sr501_kthread_func(void *data)
{
    struct sr501_struct *sr501 = data;
    while(!kthread_should_stop())
    {
        status = gpiod_get_value(sr501->gpiod);
        printk("%s line %d: gpio %d, status %d\n", __FUNCTION__, __LINE__, sr501->gpio, status);
        
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(5*HZ);
    }

    return 0;
}


/* 按键读取驱动 file_operations */
static struct file_operations xxh_sr501_drv = {
    .owner = THIS_MODULE,
    .read  = sensor_sr501_drv_read,
    .fasync = sensor_sr501_drv_fasync,
};

/* 中断服务函数 */
static irqreturn_t xxh_sensor_sr501_isr(int irq, void *dev_id)
{
    struct sr501_struct *sr501 = dev_id;

    status = gpiod_get_value(sr501->gpiod);
    printk("%s line %s: gpio %d, status %d\n", __FUNCTION__, __LINE__, sr501->gpio, status);
    wake_up_interruptible(&sr501_waitqueue);

    return IRQ_HANDLED;
}


/*
 * 4、从platform device获取GPIO
 *    把file_operations结构体告诉内核：注册驱动程序
 */
static int xxh_sensor_sr501_probe(struct platform_device *dev)
{
    int err, index;
    int count;
    struct device_node *np;
    enum of_gpio_flags flags;
    unsigned l_flags = GPIOF_IN;


    /* 设备节点获取 */
    np = dev->dev.of_node;
    
    /* 4.1 从设备树获取gpios属性 */
    count  = of_gpio_count(np);
    printk("The number of gpios is %d\n", count);

    sensor_sr501 = kzalloc(sizeof(struct sr501_struct)*count, GFP_KERNEL);
    if(sensor_sr501 == NULL)
        return -1;

    for(index=0; index < count; index++) {
        /* 获取gpio号, 转化gpio描述符为一个整数值(未来可能会消失)
        desc->gdev->base + (desc - &desc->gdev->descs[0]);
        */
        sensor_sr501[index].gpio = of_get_gpio_flags(np, index, &flags);
        printk("get flags: %#x \n", flags);
        
        /* 获取gpio描述符 */
        sensor_sr501[index].gpiod = gpio_to_desc(sensor_sr501[index].gpio);
        gpiod_direction_input(sensor_sr501[index].gpiod);

        /* 获取GPIO中断号 */
        sensor_sr501[index].irq = gpiod_to_irq(sensor_sr501[index].gpiod);
        if (sensor_sr501[index].irq < 0) {
            err = sensor_sr501[index].irq;
            dev_err(&dev->dev,
                "Unable to get irq number for GPIO %d, error %d\n",
                sensor_sr501[index].gpio, err);
            return err;
        }
        else {
            printk("%s %s line %d: get irq number is %d\n", __FILE__, __FUNCTION__, __LINE__, sensor_sr501[index].irq);
        }
        /* 申请中断 */
        err = request_irq(sensor_sr501[index].irq, xxh_sensor_sr501_isr, 
                          IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, 
                          "xxh_sensor_sr501", &sensor_sr501[index]);

        
        sr501_task = kthread_create(sensor_sr501_kthread_func, &sensor_sr501[index], "sr501");
        if (IS_ERR(sr501_task)) {
            pr_err("Failed to create AML debugger thread.\n");
            return PTR_ERR(sr501_task);
        }
        wake_up_process(sr501_task);
    }

    /* 注册file_operations结构体 */
    major = register_chrdev(0, "xxh_sr501", &xxh_sr501_drv);
    sr501_class = class_create(THIS_MODULE, "xxhsr501");  /* /sys/class/xxhkey */
    err = PTR_ERR(sr501_class);
    if (IS_ERR(sr501_class)) {
        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
        unregister_chrdev(major, "xxh_sr501");
        return -1;
    }

    device_create(sr501_class, NULL, MKDEV(major, 0), NULL, "xxhsr501"); /* /dev/xxhkey */

    return 0;
}

static int xxh_sensor_sr501_remove(struct platform_device *dev)
{
    struct device_node *np;
    int index, count;
    int ret;
    
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    device_destroy(sr501_class, MKDEV(major, 0));
    class_destroy(sr501_class);
    unregister_chrdev(major, "xxh_key");

    /* 设备节点获取 */
    np = dev->dev.of_node;
    count = of_gpio_count(np);
    for(index = 0; index < count; index++) {
        free_irq(sensor_sr501[index].irq, &sensor_sr501[index]);
        gpiod_put(sensor_sr501[index].gpiod);
    }

    kfree(sensor_sr501);
    
    return 0;
}


static const struct of_device_id sensor_sr501_dev[] = {
    {.compatible = "xxh,sensor_sr501_drv"},
    {},
};

/* 1、定义platform_drver结构体 */
static struct platform_driver xxh_sensor_sr501_driver = {
    .probe  = xxh_sensor_sr501_probe,
    .remove = xxh_sensor_sr501_remove,
    .driver = {
        .name   = "xxh_sensor_sr501",
        .of_match_table = sensor_sr501_dev,
    },
};


static int __init sensor_sr501_init(void)
{
    int err;
    printk("%s line %d\n", __FUNCTION__, __LINE__);
    err = platform_driver_register(&xxh_sensor_sr501_driver);

    return err;
}


static void __exit sensor_sr501_exit(void)
{
    printk("%s line %d\n", __FUNCTION__, __LINE__);
    kthread_stop(sr501_task);
    platform_driver_unregister(&xxh_sensor_sr501_driver);
    return;
}

/* 7. 其他完善：提供设备信息，自动创建设备节点                                     */

module_init(sensor_sr501_init);
module_exit(sensor_sr501_exit);

MODULE_LICENSE("GPL");

